grammar complexCalculator;

unit: (defUnit | funcUnit)* EOF;

defUnit: varUnit;

varUnit: type varDef (',' varDef)* ';' ;

type
    : Int
    | Float
    ;

varDef: 
    Identifier
    | Identifier '=' initVal
    ;

initVal: exp ;

funcUnit: type Identifier '(' (funcFParams)? ')' block;

funcFParams: funcFParam (',' funcFParam )*;

funcFParam: type Identifier;

block: '{' (defUnit)* (stat)* '}';

stat
    : lVal '=' exp ';'  # statAssign
    | (exp)?';'   # statExp
    | block  # statBlock
    ;

lVal : Identifier ;

exp
    : number  # expNumber
    | Lparen exp Rparen  # expParen
    | <assoc=right> exp OpPow exp  # expPow
    | opUnary exp  # expUnary
    | exp opMulDiv  exp  # expMulDiv
    | exp opAddSub exp  # expAddSub
    | Identifier '(' (funcRParams)?')'  # funcCall
    | Identifier  # identifier
    ;

number
    : INT
    | FLOAT
    ;

opUnary
    : Plus
    | Minus
    ;

opMulDiv
    : Mul
    | Div
    ;

opAddSub
    : Plus
    | Minus
    ;

funcRParams: funcRParam (',' funcRParam)*;
funcRParam: exp;

Int: 'int';
Float: 'float';
OpPow : '^';
Lparen : '(';
Rparen : ')';
Plus: '+';
Minus: '-';
Mul: '*';
Div: '/';
INT: Digit+;
FLOAT : Digit+ '.' Digit*;

Identifier
    : [a-zA-Z_][a-zA-Z_0-9]*
    ;
WS : 
    [ \t\r\n] -> skip
    ;

fragment
Digit
    : [0-9]
    ;